<template>
  <div id="slide_element"
       ref="element"
       :title="Title"
       :style="elStyle"
       :class="{active:Activated || Selected}"
       @pointerdown.left="elementMouseDown('move')"
       @click.stop="$emit('Click')">
    <div v-show="isChangeSize && Activated && (!LockWidth && !LockHeight)" class="mainpptr_tl mainpptr_to"
         @pointerdown.stop="elementMouseDown('setTopLeftCorner')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && !LockHeight" class="mainpptr_tc mainpptr_to"
         @pointerdown.stop="elementMouseDown('setTop')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && (!LockWidth && !LockHeight)" class="mainpptr_tr mainpptr_to"
         @pointerdown.stop="elementMouseDown('setTopRightCorner')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && !LockWidth" class="mainpptr_cl mainpptr_to"
         @pointerdown.stop="elementMouseDown('setLeft')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && !LockWidth" class="mainpptr_cr mainpptr_to"
         @pointerdown.stop="elementMouseDown('setRight')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && (!LockWidth && !LockHeight)" class="mainpptr_bl mainpptr_to"
         @pointerdown.stop="elementMouseDown('setLowerLeftCorner')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && !LockHeight" class="mainpptr_bc mainpptr_to"
         @pointerdown.stop="elementMouseDown('setBottom')" @contextmenu.stop.prevent/>

    <div v-show="isChangeSize && Activated && (!LockWidth && !LockHeight)" class="mainpptr_br mainpptr_to"
         @pointerdown.stop="elementMouseDown('setLowerRightCorner')" @contextmenu.stop.prevent/>

    <editor-context-menu :ContextMenu="contextMenu"
                         :ShowMenu="Activated"
                         @Copy="$emit('Copy',ID)"
                         @Delete="$emit('Delete',ID)"
                         @FullSreen="$emit('FullSreen',ID)"
                         @PreviousLayer="$emit('PreviousLayer',ID)"
                         @NextLayer="$emit('NextLayer',ID)"
                         @TopLayer="$emit('TopLayer',ID)"
                         @UnderLayer="$emit('UnderLayer',ID)"
                         @SaveLocal="saveLocal"
                         v-if="ShowContextMenu"
    />
    <slot>

    </slot>
  </div>
</template>
<script>
  import EditorContextMenu from './EditorContextMenu'

  let remote = ''
  let fs = ''

  export default {
    name: 'SlideElement',
    components: {EditorContextMenu},
    data () {
      return {
        isAppend: false,
        cursorState: '',
        startLocation: null,
        elLocation: null,
        elSize: null,
        borderWidth: 0,
        contextMenuLoc: null,
        contextMenuSize: null,
        contextMenu: [
          {
            id: 'Copy',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/fz.png',
            text: '复制',
            event: 'Copy',
            disable: false,
            show: true
          },
          {
            id: 'Delete',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/sc.png',
            text: '删除',
            event: 'Delete',
            disable: false,
            show: true
          },
          {
            id: 'FullSreen',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/qp.png',
            text: '满屏',
            event: 'FullSreen',
            disable: false,
            show: true
          },
          {
            id: 'PreviousLayer',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/sy.png',
            text: '上一层',
            event: 'PreviousLayer',
            disable: false,
            show: true
          },
          {
            id: 'NextLayer',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/xy.png',
            text: '下一层',
            event: 'NextLayer',
            disable: false,
            show: true
          },
          {
            id: 'TopLayer',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/zd2.png',
            text: '置于顶层',
            event: 'TopLayer',
            disable: false,
            show: true
          },
          {
            id: 'UnderLayer',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/zd1.png',
            text: '置于底层',
            event: 'UnderLayer',
            disable: false,
            show: true
          },
          {
            id: 'SaveLocal',
            icon: (process.browser ? '/static' : remote.getGlobal('staticPath')) + '/img/catalog/bc.png',
            text: '保存至本地',
            event: 'SaveLocal',
            disable: false,
            show: !process.browser && this.isShowSaveLocal
          }
        ]
      }
    },
    props: {
      ID: {type: String},
      Title: {type: String},
      Selected: {type: Boolean, default: false},
      Activated: {type: Boolean, default: false},
      isShowSaveLocal: {type: Boolean, default: false},
      ElementStyle: {type: Object, default: {}},
      Location: {
        type: Object,
        default: () => {
          return {left: 0, top: 0}
        }
      },
      Size: {
        type: Object,
        default: () => {
          return {width: 0, height: 0}
        }
      },
      ContainerSize: {
        type: Object,
        default: () => {
          return {width: 0, height: 0}
        }
      },
      LockWidth: {type: Boolean, default: false},
      LockHeight: {type: Boolean, default: false},
      LockMove: {type: Boolean, default: false},
      LockSelect: {type: Boolean, default: false},
      KeyboardMove: {type: Boolean, default: true},
      isChangeSize: {type: Boolean, default: true},
      ShowContextMenu: {type: Boolean, default: true}
    },
    comments: ['EditorContextMenu'],
    computed: {
      elStyle: function () {
        let style = {}
        if (this.Activated) style = {...this.ElementStyle}

        if (this.elLocation) {
          style['margin-left'] = `${this.elLocation.left}px`
          style['margin-top'] = `${this.elLocation.top}px`
        }
        if (this.elSize) {
          style['width'] = `${this.elSize.width + 2}px`
          style['height'] = `${this.elSize.height + 2}px`
        }
        return style
      }
    },
    watch: {
      elStyle: function (n, o) {
        let el = this.$refs.element
        if (el && el.style && el.style.borderWidth) {
          this.borderWidth =
            2 *
            (isNaN(parseInt(el.style.borderWidth))
              ? 0
              : parseInt(el.style.borderWidth))
        }
      },
      Location: function (n, o) {
        if (!n) return
        if (isNaN(n.left)) {
          this.elLocation.left = parseInt(n.left)
        }
        if (isNaN(n.top)) {
          this.elLocation.top = parseInt(n.top)
        }
        if (this.ID) this.initElementLocSize()
      },
      Size: function (n, o) {
        if (!n) return
        if (isNaN(n.width)) {
          this.elSize.width = parseInt(n.width)
        }
        if (isNaN(n.height)) {
          this.elSize.height = parseInt(n.height)
        }
        if (this.ID) this.initElementLocSize()
      }
    },
    mounted: function () {
      let self = this
      this.$eventBus.$on('keydown', this.useKeyboardMoveElement)
      this.$nextTick(function () {
        let el = this.$refs.element
        if (!el || !el.offsetParent) return
        this.initElementLocSize()
        el.offsetParent.addEventListener('pointermove', this.containerMouseMove)
        el.offsetParent.addEventListener('pointerup', () => {
          if (self.isAppend) {
            self.isAppend = false
            self.$emit('appended', self.ID)
          }
        })
        self.$emit('SlideElementFinish', this.ID)
      })
      document.addEventListener('pointerup', function (e) {
        self.cursorState = null
        self.startLocation = null
        self.contextMenuLoc = null
        self.$nextTick(function () {
          self.$emit('LocSizeChanged', {...self.elLocation, ...self.elSize})
        })
      })
    },
    methods: {
      initElementLocSize: function () {
        if (!this.ContainerSize) return
        if (this.Location) {
          let loc = {left: 0, top: 0}
          if (isNaN(this.Location.left)) {
            loc.left = isNaN(parseInt(this.Location.left))
              ? 0
              : parseInt(this.Location.left)
          } else {
            loc.left = this.ContainerSize.width * this.Location.left
          }
          if (isNaN(this.Location.top)) {
            loc.top = isNaN(parseInt(this.Location.top))
              ? 0
              : parseInt(this.Location.top)
          } else {
            loc.top = this.ContainerSize.height * this.Location.top
          }
          this.elLocation = loc
        }

        if (this.Size) {
          let size = {width: 0, height: 0}
          if (isNaN(this.Size.width)) {
            size.width = isNaN(parseInt(this.Size.width))
              ? 0
              : parseInt(this.Size.width)
          } else {
            size.width = this.ContainerSize.width * this.Size.width
          }
          if (isNaN(this.Size.height)) {
            size.height = isNaN(parseInt(this.Size.height))
              ? 0
              : parseInt(this.Size.height)
          } else {
            size.height = this.ContainerSize.height * this.Size.height
          }
          this.elSize = size
        }
      },
      containerMouseMove: function () {
        if (!this.startLocation || this.LockMove || !this.Activated) return
        switch (this.cursorState) {
          case 'move':
            if (!this.LockMove) this.useMouseMoveElement()
            break
          case 'setLeft':
            this.widenToLeft(event)
            break
          case 'setRight':
            this.widenToRight(event)
            break
          case 'setTop':
            this.upToHigh(event)
            break
          case 'setBottom':
            this.downToHigh(event)
            break
          case 'setTopLeftCorner':
            if (!this.LockWidth) this.widenToLeft(event)
            if (!this.LockHeight) this.upToHigh(event)
            break
          case 'setTopRightCorner':
            if (!this.LockWidth) this.widenToRight(event)
            if (!this.LockHeight) this.upToHigh(event)
            break
          case 'setLowerLeftCorner':
            if (!this.LockWidth) this.widenToLeft(event)
            if (!this.LockHeight) this.downToHigh(event)
            break
          case 'setLowerRightCorner':
            if (!this.LockWidth) this.widenToRight(event)
            if (!this.LockHeight) this.downToHigh(event)
            break
          default:
            break
        }
        if (this.startLocation) {
          this.$emit('LocSizeChanging', {
            ID: this.ID,
            ...this.elSize,
            ...this.elLocation,
            offset: {x: event.offsetX, y: event.offsetY}
          })
          this.startLocation = {x: event.clientX, y: event.clientY}
        }
      },
      elementMouseDown: function (cursorState) {
        this.cursorState = cursorState
        this.startLocation = {x: event.clientX, y: event.clientY}
      },

      // 使用键盘移动元素
      useKeyboardMoveElement: function () {
        if (!this.Activated || this.LockMove || !this.KeyboardMove) return
        if ([37, 38, 39, 40].indexOf(event.keyCode) === -1) return
        let elSize = this.elSize
        let elLocation = this.elLocation
        let containerSize = this.ContainerSize
        if (!elSize || !elLocation || !containerSize) return
        if (event.keyCode === 37 && !elLocation.left) return
        if (event.keyCode === 38 && !elLocation.top) return
        if (event.keyCode === 39 && elLocation.left + elSize.width === containerSize.width - this.borderWidth) return
        if (event.keyCode === 40 && elLocation.top + elSize.height === containerSize.height - this.borderWidth) return

        // 左移
        if (event.keyCode === 37) {
          //  && elLocation.left > 0
          // 左边距=左边距==0？0：左边距-2；
          elLocation.left = elLocation.left - 2 > 0 ? elLocation.left - 2 : 0
        } else if (event.keyCode === 38) {
          //  && elLocation.top > 0
          // 上移
          // 上边距=上边距==0？0：上边距-2；
          elLocation.top = elLocation.top - 2 > 0 ? elLocation.top - 2 : 0
        } else if (
          event.keyCode === 39
        ) {
          // &&
          // elLocation.left + elSize.width < containerSize.width - this.borderWidth
          // 右移
          // 左边距=左边距+2>容器宽度-元素宽度？容器宽度-元素宽度：左边距+2；
          elLocation.left =
            elLocation.left + 2 > containerSize.width - elSize.width
              ? containerSize.width - elSize.width
              : elLocation.left + 2
        } else if (
          event.keyCode === 40
        ) {
          //  &&
          // elLocation.top + elSize.height < containerSize.height - this.borderWidth
          // 下移
          // 上边距=上边距+2>容器高度-元素高度？容器高度-元素高度：上边距+2；
          elLocation.top =
            elLocation.top + elSize.height + 2 > containerSize.height
              ? containerSize.height - elSize.height
              : elLocation.top + 2
        }

        this.$emit('LocSizeChanging', {
          ID: this.ID,
          ...this.elSize,
          ...this.elLocation
        })
      },
      // 使用鼠标移动元素
      useMouseMoveElement: function () {
        if (!this.Activated || event.ctrlKey) return
        let startLocation = this.startLocation
        let containerSize = this.ContainerSize
        let elLocation = this.elLocation
        let elSize = this.elSize
        // 点击坐标对象为空则终止操作
        if (!startLocation || !containerSize || !elLocation || !elSize) return

        // 超出容器左边
        if (elLocation.left + (event.clientX - startLocation.x) < 0) {
          elLocation.left = 0
        } else if (
          elLocation.left + elSize.width + (event.clientX - startLocation.x) >
          containerSize.width - this.borderWidth
        ) {
          elLocation.left = containerSize.width - elSize.width - this.borderWidth
        } else {
          elLocation.left += event.clientX - startLocation.x
        }
        // 超出容器上边
        if (elLocation.top + (event.clientY - startLocation.y) < 0) {
          elLocation.top = 0
        } else if (
          elLocation.top + elSize.height + (event.clientY - startLocation.y) >
          containerSize.height - this.borderWidth
        ) {
          elLocation.top =
            containerSize.height - elSize.height - this.borderWidth
        } else {
          elLocation.top += event.clientY - startLocation.y
        }
      },
      // 元素向左边拖动
      widenToLeft: function (ev) {
        let startLocation = this.startLocation
        let elLocation = this.elLocation
        let elSize = this.elSize
        if (!startLocation || !elLocation || !elSize) return
        // 向左拉宽
        if (startLocation.x > ev.clientX) {
          if (elLocation.left === 0) return
          if (elLocation.left - (startLocation.x - ev.clientX) <= 0) {
            elSize.width += elLocation.left
            elLocation.left = 0
          } else {
            elSize.width += startLocation.x - ev.clientX
            elLocation.left -= startLocation.x - ev.clientX
          }
        } else if (startLocation.x < ev.clientX) {
          // 向右拉宽
          if (!elSize.width) return
          let right = elLocation.left + elSize.width
          if (elLocation.left + (ev.clientX - startLocation.x) >= right) {
            elSize.width = 0
            elLocation.left = right
          } else {
            elSize.width -= ev.clientX - startLocation.x
            elLocation.left += ev.clientX - startLocation.x
          }
        }
      },
      // 元素向右边拖动
      widenToRight: function (ev) {
        let startLocation = this.startLocation
        let containerSize = this.ContainerSize
        let elLocation = this.elLocation
        let elSize = this.elSize
        if (!startLocation || !containerSize || !elLocation || !elSize) return
        // 向左拉宽
        if (startLocation.x > ev.clientX) {
          if (!elSize.width) return
          if (elSize.width - (startLocation.x - ev.clientX) <= 0) {
            elSize.width = 0
          } else {
            elSize.width -= startLocation.x - ev.clientX
          }
        } else if (startLocation.x < ev.clientX) {
          // 向右拉宽
          if (elSize.width === containerSize.width - elLocation.left) return
          if (
            elSize.width + (ev.clientX - startLocation.x) >=
            containerSize.width - elLocation.left - this.borderWidth
          ) {
            elSize.width =
              containerSize.width - elLocation.left - this.borderWidth
          } else {
            elSize.width += ev.clientX - startLocation.x
          }
        }
      },
      // 元素向顶部拖动
      upToHigh: function (ev) {
        let startLocation = this.startLocation
        let elLocation = this.elLocation
        let elSize = this.elSize
        if (!startLocation || !elLocation || !elSize) return
        // 向上拉宽
        if (startLocation.y > ev.clientY) {
          if (elLocation.top === 0) return
          if (elLocation.top - (startLocation.y - ev.clientY) <= 0) {
            elSize.height += elLocation.top
            elLocation.top = 0
          } else {
            elSize.height += startLocation.y - ev.clientY
            elLocation.top -= startLocation.y - ev.clientY
          }
        } else if (startLocation.y < ev.clientY) {
          // 向下拉宽
          if (!elSize.height) return
          let bottom = elLocation.top + elSize.height
          if (elLocation.top + (ev.clientY - startLocation.y) >= bottom) {
            elSize.height = 0
            elLocation.top = bottom
          } else {
            elSize.height -= ev.clientY - startLocation.y
            elLocation.top += ev.clientY - startLocation.y
          }
        }
      },
      // 元素向底部拖动
      downToHigh: function (ev) {
        let startLocation = this.startLocation
        let containerSize = this.ContainerSize
        let elLocation = this.elLocation
        let elSize = this.elSize
        if (!startLocation || !containerSize || !elLocation || !elSize) return
        // 向下拉宽
        if (startLocation.y > ev.clientY) {
          if (!elSize.height) return
          if (elSize.height - (startLocation.y - ev.clientY) <= 0) {
            elSize.height = 0
          } else {
            elSize.height -= startLocation.y - ev.clientY
          }
        } else if (startLocation.y < ev.clientY) {
          // 向上拉宽
          if (elSize.height === containerSize.height - elLocation.top) return
          if (
            elSize.height + (ev.clientY - startLocation.y) >=
            containerSize.height - elLocation.top - this.borderWidth
          ) {
            elSize.height =
              containerSize.height - elLocation.top - this.borderWidth
          } else {
            elSize.height += ev.clientY - startLocation.y
          }
        }
      },

      // ===========================================================
      // 设置拖拽方向
      setDragDirection: function (cursorState) {
        this.cursorState = cursorState
        this.isAppend = true
        if (this.Location) {
          let loc = {left: 0, top: 0}

          if (isNaN(this.Location.left)) {
            loc.left =
              parseInt(this.Location.left) === 'NaN'
                ? 0
                : parseInt(this.Location.left)
          } else {
            loc.left = this.ContainerSize.width * this.Location.left
          }
          if (isNaN(this.Location.top)) {
            loc.top =
              parseInt(this.Location.top) === 'NaN'
                ? 0
                : parseInt(this.Location.top)
          } else {
            loc.top = this.ContainerSize.height * this.Location.top
          }
          this.elLocation = {...loc}
          this.startLocation = {...loc}
        }
      },
      // 设置元素位置
      setLocation: function (loc) {
        if (!loc || loc.left === undefined || loc.top === undefined) return
        this.elLocation = {left: loc.left, top: loc.top}
      },
      saveLocal: function () {
        let self = this
        let activeEle = this.$store.state.slideEditor.activeElement
        if (!activeEle) return this.$alert('请选中导出元素')
        let exportFile = this.$store.state.slideEditor.files.find(x => {
          return x.ID === this.$store.state.slideEditor.activeElement.path
        })
        if (!exportFile) return this.$alert('未找到导出元素')

        let res = remote.dialog.showSaveDialog(remote.getCurrentWindow(), {
          title: '保存至本地',
          defaultPath: this.$store.state.slideEditor.slide.element.find(x => {
            return x.type === 'TEXT'
          }).text,
          filters: [
            {
              name: 'Image',
              extensions: ['png', 'jpg']
            }
          ]
        })

        // 过滤data:URL
        let base64Data = exportFile.IMG.replace(/^data:image\/\w+;base64,/, '')
        let dataBuffer = Buffer.from(base64Data, 'base64')
        fs.writeFile(res, dataBuffer, function (err) {
          if (err) {
            self.$alert('保存错误')
            self.$logger.error(err)
          }
        })
      }
    }
  }
</script>
<style>
  #slide_element {
    text-align: left;
    position: absolute;
  }

  #slide_element .active {
    float: left;
    margin: 100px;
    border: 1px dashed #999;
    position: relative;
  }

  #slide_element .mainpptr_br {
    bottom: -4px;
    right: -4px;
    cursor: se-resize;
  }

  #slide_element .mainpptr_bc {
    left: calc(50% - 4px);
    bottom: -4px;
    cursor: s-resize;
  }

  #slide_element .mainpptr_bl {
    left: -4px;
    bottom: -4px;
    cursor: sw-resize;
  }

  #slide_element .mainpptr_cr {
    top: calc(50% - 4px);
    right: -4px;
    cursor: e-resize;
  }

  #slide_element .mainpptr_cl {
    top: calc(50% - 4px);
    left: -4px;
    cursor: w-resize;
  }

  #slide_element .mainpptr_tr {
    top: -4px;
    right: -4px;
    cursor: ne-resize;
  }

  #slide_element .mainpptr_tc {
    top: -4px;
    left: calc(50% - 4px);
    cursor: n-resize;
  }

  #slide_element .mainpptr_tl {
    top: -4px;
    left: -4px;
    cursor: nw-resize;
  }

  #slide_element .mainpptr_to {
    width: 8px;
    height: 8px;
    border: 1px solid #999;
    background: white;
    position: absolute;
    z-index: 1;
  }

  /*#slide_element .rootContextMenu {*/
  /*z-index: 999;*/
  /*width: 130px;*/
  /*background: white;*/
  /*position: absolute;*/
  /*border: 1px solid #ddd;*/
  /*border-radius: 4px;*/
  /*}*/

  /*#slide_element .folderContextMenuul {*/
  /*width: 100%;*/
  /*height: 100%;*/
  /*!*float: left;*!*/
  /*margin: 0 auto;*/
  /*padding: 0;*/
  /*font-size: 14px;*/
  /*}*/

  /*#slide_element .folderContextMenuul li {*/
  /*list-style-type: none;*/
  /*width: 100%;*/
  /*height: 28px;*/
  /*!*line-height: 35px;*!*/
  /*!*float: left;*!*/
  /*cursor: pointer;*/
  /*}*/

  /*#slide_element .folderContextMenuul li span {*/
  /*line-height: 28px;*/
  /*cursor: inherit;*/
  /*}*/

  /*#slide_element .folderContextMenuul li img {*/
  /*height: 100%;*/
  /*padding: 7px;*/
  /*padding-right: 3px;*/
  /*cursor: inherit;*/
  /*}*/

  /*#slide_element .folderContextMenuul li:hover {*/
  /*background: #288ed3;*/
  /*color: white;*/
  /*}*/

  /*#slide_element .folderContextMenuline {*/
  /*width: calc(100% - 10px);*/
  /*height: 1px;*/
  /*background: #ddd;*/
  /*float: left;*/
  /*margin: 0 5px;*/
  /*}*/

  /* 淡入 */

  @keyframes fadein {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }

  /* 淡入-从上 */

  @keyframes fadeinT {
    0% {
      opacity: 0;
      transform: translateY(-100px);
    }
    100% {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* 淡入-从右 */

  @keyframes fadeinR {
    0% {
      opacity: 0;
      transform: translateX(100px);
    }
    100% {
      opacity: 1;
      transform: translateX(0);
    }
  }

  /* 淡入-从下 */

  @keyframes fadeinB {
    0% {
      opacity: 0;
      transform: translateY(100px);
    }
    100% {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* 淡入-从左 */

  @keyframes fadeinL {
    0% {
      opacity: 0;
      transform: translateX(-100px);
    }
    100% {
      opacity: 1;
      transform: translateX(0);
    }
  }

  /* 淡出 */

  @keyframes fadeout {
    0% {
      opacity: 1;
    }
    100% {
      opacity: 0;
    }
  }

  /* 淡出-向上 */

  @keyframes fadeoutT {
    0% {
      opacity: 1;
      transform: translateY(0);
    }
    100% {
      opacity: 0;
      transform: translateY(-100px);
    }
  }

  /* 淡出-向右 */

  @keyframes fadeoutR {
    0% {
      opacity: 1;
      transform: translateX(0);
    }
    100% {
      opacity: 0;
      transform: translateX(100px);
    }
  }

  /* 淡出-向下 */

  @keyframes fadeoutB {
    0% {
      opacity: 1;
      transform: translateY(0);
    }
    100% {
      opacity: 0;
      transform: translateY(100px);
    }
  }

  /* 淡出-向左 */

  @keyframes fadeoutL {
    0% {
      opacity: 1;
      transform: translateX(0);
    }
    100% {
      opacity: 0;
      transform: translateX(-100px);
    }
  }

  /* 弹跳 */

  @keyframes bounce {
    0%,
    20%,
    50%,
    80%,
    100% {
      transform: translateY(0);
    }
    40% {
      transform: translateY(-30px);
    }
    60% {
      transform: translateY(-15px);
    }
  }

  /* 弹入 */

  @keyframes bouncein {
    0% {
      opacity: 0;
      transform: scale(0.3);
    }
    50% {
      opacity: 1;
      transform: scale(1.05);
    }
    70% {
      transform: scale(0.9);
    }
    100% {
      transform: scale(1);
    }
  }

  /* 弹入-从上 */

  @keyframes bounceinT {
    0% {
      opacity: 0;
      transform: translateY(-100px);
    }
    60% {
      opacity: 1;
      transform: translateY(30px);
    }
    80% {
      transform: translateY(-10px);
    }
    100% {
      transform: translateY(0);
    }
  }

  /* 弹入-从右 */

  @keyframes bounceinR {
    0% {
      opacity: 0;
      transform: translateX(100px);
    }
    60% {
      opacity: 1;
      transform: translateX(-30px);
    }
    80% {
      transform: translateX(10px);
    }
    100% {
      transform: translateX(0);
    }
  }

  /* 弹入-从下 */

  @keyframes bounceinB {
    0% {
      opacity: 0;
      transform: translateY(100px);
    }
    60% {
      opacity: 1;
      transform: translateY(-30px);
    }
    80% {
      transform: translateY(10px);
    }
    100% {
      transform: translateY(0);
    }
  }

  /* 弹入-从左 */

  @keyframes bounceinL {
    0% {
      opacity: 0;
      transform: translateX(-100px);
    }
    60% {
      opacity: 1;
      transform: translateX(30px);
    }
    80% {
      transform: translateX(-10px);
    }
    100% {
      transform: translateX(0);
    }
  }

  /* 弹出 */

  @keyframes bounceout {
    0% {
      transform: scale(1);
    }
    25% {
      transform: scale(0.95);
    }
    50% {
      opacity: 1;
      transform: scale(1.1);
    }
    100% {
      opacity: 0;
      transform: scale(0.3);
    }
  }

  /* 弹出-向上*/

  @keyframes bounceoutT {
    0% {
      transform: translateY(0);
    }
    20% {
      opacity: 1;
      transform: translateY(20px);
    }
    100% {
      opacity: 0;
      transform: translateY(-100px);
    }
  }

  /* 弹出-向右*/

  @keyframes bounceoutR {
    0% {
      transform: translateX(0);
    }
    20% {
      opacity: 1;
      transform: translateX(-20px);
    }
    100% {
      opacity: 0;
      transform: translateX(100px);
    }
  }

  /* 弹出-向下 */

  @keyframes bounceoutB {
    0% {
      transform: translateY(0);
    }
    20% {
      opacity: 1;
      transform: translateY(-20px);
    }
    100% {
      opacity: 0;
      transform: translateY(100px);
    }
  }

  /* 弹出-向左 */

  @keyframes bounceoutL {
    0% {
      transform: translateX(0);
    }
    20% {
      opacity: 1;
      transform: translateX(20px);
    }
    100% {
      opacity: 0;
      transform: translateX(-200px);
    }
  }

  /* 转入 */

  @keyframes rotatein {
    0% {
      opacity: 0;
      transform: rotate(-200deg);
    }
    100% {
      opacity: 1;
      transform: rotate(0);
    }
  }

  /* 转入-从左上 */

  @keyframes rotateinLT {
    0% {
      transform-origin: left bottom;
      transform: rotate(-90deg);
      opacity: 0;
    }
    100% {
      transform-origin: left bottom;
      transform: rotate(0);
      opacity: 1;
    }
  }

  /* 转入-从左下 */

  @keyframes rotateineftB {
    0% {
      transform-origin: left bottom;
      transform: rotate(90deg);
      opacity: 0;
    }
    100% {
      transform-origin: left bottom;
      transform: rotate(0);
      opacity: 1;
    }
  }

  /* 转入-从右上 */

  @keyframes rotateinRT {
    0% {
      transform-origin: right bottom;
      transform: rotate(90deg);
      opacity: 0;
    }
    100% {
      transform-origin: right bottom;
      transform: rotate(0);
      opacity: 1;
    }
  }

  /* 转入-从右下*/

  @keyframes rotateinRB {
    0% {
      transform-origin: right bottom;
      transform: rotate(-90deg);
      opacity: 0;
    }
    100% {
      transform-origin: right bottom;
      transform: rotate(0);
      opacity: 1;
    }
  }

  /* 转出 */

  @keyframes rotateout {
    0% {
      transform-origin: center center;
      transform: rotate(0);
      opacity: 1;
    }
    100% {
      transform-origin: center center;
      transform: rotate(200deg);
      opacity: 0;
    }
  }

  /* 转出-向左上 */

  @keyframes rotateoutLT {
    0% {
      transform-origin: left bottom;
      transform: rotate(0);
      opacity: 1;
    }
    100% {
      transform-origin: left bottom;
      transform: rotate(-90deg);
      opacity: 0;
    }
  }

  /* 转出-向左下 */

  @keyframes rotateoutLB {
    0% {
      transform-origin: left bottom;
      transform: rotate(0);
      opacity: 1;
    }
    100% {
      transform-origin: left bottom;
      transform: rotate(90deg);
      opacity: 0;
    }
  }

  /* 转出-向右上 */

  @keyframes rotateoutRT {
    0% {
      transform-origin: right bottom;
      transform: rotate(0);
      opacity: 1;
    }
    100% {
      transform-origin: right bottom;
      transform: rotate(90deg);
      opacity: 0;
    }
  }

  /* 转出-向右下 */

  @keyframes rotateoutBR {
    0% {
      transform-origin: right bottom;
      transform: rotate(0);
      opacity: 1;
    }
    100% {
      transform-origin: right bottom;
      transform: rotate(-90deg);
      opacity: 0;
    }
  }

  /* 翻转 */

  @keyframes flip {
    0% {
      transform: perspective(400px) rotateY(0);
      animation-timing-function: ease-out;
    }
    40% {
      transform: perspective(400px) translateZ(150px) rotateY(170deg);
      animation-timing-function: ease-out;
    }
    50% {
      transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
      animation-timing-function: ease-in;
    }
    80% {
      transform: perspective(400px) rotateY(360deg) scale(0.95);
      animation-timing-function: ease-in;
    }
    100% {
      transform: perspective(400px) scale(1);
      animation-timing-function: ease-in;
    }
  }

  /* 翻入-X轴 */

  @keyframes flipinX {
    0% {
      transform: perspective(400px) rotateX(90deg);
      opacity: 0;
    }
    40% {
      transform: perspective(400px) rotateX(-10deg);
    }
    70% {
      transform: perspective(400px) rotateX(10deg);
    }
    100% {
      transform: perspective(400px) rotateX(0);
      opacity: 1;
    }
  }

  /* 翻入-Y轴 */

  @keyframes flipinY {
    0% {
      transform: perspective(400px) rotateY(90deg);
      opacity: 0;
    }
    40% {
      transform: perspective(400px) rotateY(-10deg);
    }
    70% {
      transform: perspective(400px) rotateY(10deg);
    }
    100% {
      transform: perspective(400px) rotateY(0);
      opacity: 1;
    }
  }

  /* 翻出-X轴 */

  @keyframes flipoutX {
    0% {
      transform: perspective(400px) rotateX(0);
      opacity: 1;
    }
    100% {
      transform: perspective(400px) rotateX(90deg);
      opacity: 0;
    }
  }

  /* 翻出-Y轴 */

  @keyframes flipoutY {
    0% {
      transform: perspective(400px) rotateY(0);
      opacity: 1;
    }
    100% {
      transform: perspective(400px) rotateY(90deg);
      opacity: 0;
    }
  }

  /* 闪烁 */

  @keyframes flash {
    0%,
    50%,
    100% {
      opacity: 1;
    }
    25%,
    75% {
      opacity: 0;
    }
  }

  /* 震颤 */

  @keyframes shake {
    0%,
    100% {
      transform: translateX(0);
    }
    10%,
    30%,
    50%,
    70%,
    90% {
      transform: translateX(-10px);
    }
    20%,
    40%,
    60%,
    80% {
      transform: translateX(10px);
    }
  }

  /* 摇摆 */

  @keyframes swing {
    20% {
      transform: rotate(15deg);
    }
    40% {
      transform: rotate(-10deg);
    }
    60% {
      transform: rotate(5deg);
    }
    80% {
      transform: rotate(-5deg);
    }
    100% {
      transform: rotate(0);
    }
  }

  /* 摇晃 */

  @keyframes wobble {
    0% {
      transform: translateX(0);
    }
    15% {
      transform: translateX(-100px) rotate(-5deg);
    }
    30% {
      transform: translateX(80px) rotate(3deg);
    }
    45% {
      transform: translateX(-65px) rotate(-3deg);
    }
    60% {
      transform: translateX(40px) rotate(2deg);
    }
    75% {
      transform: translateX(-20px) rotate(-1deg);
    }
    100% {
      transform: translateX(0);
    }
  }

  /* 震铃 */

  @keyframes ring {
    0% {
      transform: scale(1);
    }
    10%,
    20% {
      transform: scale(0.9) rotate(-3deg);
    }
    30%,
    50%,
    70%,
    90% {
      transform: scale(1.1) rotate(3deg);
    }
    40%,
    60%,
    80% {
      transform: scale(1.1) rotate(-3deg);
    }
    100% {
      transform: scale(1) rotate(0);
    }
  }

  /* 放大 */

  @keyframes zoomIn {
    0% {
      opacity: 0;
      transform: scale3d(0.3, 0.3, 0.3);
    }
    50% {
      opacity: 1;
    }
  }
</style>
